package com.jghz.transfer.service.impl;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;
import javax.xml.transform.stream.StreamResult;

import org.hibernate.annotations.common.util.StringHelper;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.oxm.Marshaller;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.bstek.dorado.data.entity.EntityState;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Page;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.jghz.framework.exception.AppException;
import com.jghz.framework.utils.AppUtils;
import com.jghz.framework.utils.SpringHolder;
import com.jghz.transfer.constant.ActionType;
import com.jghz.transfer.dao.CashFlowDao;
import com.jghz.transfer.entity.Logink;
import com.jghz.transfer.entity.Tbplateformcash;
import com.jghz.transfer.entity.cashFlow.ObjectFactory;
import com.jghz.transfer.entity.cashFlow.Root;
import com.jghz.transfer.entity.cashFlow.Root.Body;
import com.jghz.transfer.entity.cashFlow.Root.Body.Financiallist;
import com.jghz.transfer.entity.cashFlow.Root.Body.ShippingNoteList;
import com.jghz.transfer.entity.cashFlow.Root.Header;
import com.jghz.transfer.service.CashFlowService;
import com.jghz.transfer.service.LoginkService;

@Service
public class CashFlowServiceImpl implements CashFlowService {

	@Resource
	private CashFlowDao cashFlowDao;
	@Autowired
	private Marshaller marshaller;

	@Override
	public void load(Page<Tbplateformcash> page, Map<String, Object> params) throws Exception {
		cashFlowDao.pagingQuery(page, params);
	}

	@Override
	@Transactional
	public void save(Collection<Tbplateformcash> cols) {
		for (Tbplateformcash plateform : cols) {
			EntityState state = EntityUtils.getState(plateform);
			if (state.equals(EntityState.DELETED)) {
				if (StringHelper.isNotEmpty(plateform.getStatus()) && "Y".equals(plateform.getStatus()))
					throw new AppException("资金流水单号" + plateform.getDocumentNumber() + "不是新建状态，不能删除");
				cashFlowDao.delete(plateform);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	@Transactional
	public void send(Collection<Tbplateformcash> cols) throws Exception {
		if (cols.isEmpty()) {
			Map<String, Object> params = new ImmutableMap.Builder<String, Object>().put("status", "N")
					.put("senderCode", AppUtils.getLoginUserName()).build();
			int count = cashFlowDao.queryCountByStatus("N");
			int pageSize = 10000;
			int total = (count - 1) / pageSize + 1;

			for (int i = 1; i <= total; i++) {
				Page<Tbplateformcash> page = new Page<>(pageSize, i);
				cashFlowDao.pagingQuery(page, params);
				cols.addAll(page.getEntities());
			}
			// cols = (Collection<Tbplateformcash>)
			// cashFlowDao.queryCashByStatus("N");
		}

		// 可能存在重复流水单号
		Multimap<String, Tbplateformcash> map1 = ArrayListMultimap.create();// 存放流水单号与流水信息

		for (Tbplateformcash cash : cols) {
			String docNumber = cash.getDocumentNumber();
			if (!DateTime.parse(cash.getDateTime(), DateTimeFormat.forPattern("yyyyMMddHHmmss")).isBeforeNow())
				throw new RuntimeException("资金发生日期不能大于当前日期");
			map1.put(docNumber, cash);
		}
		for (Entry<String, Collection<Tbplateformcash>> entry : map1.asMap().entrySet()) {
			Root root = assembleRoot(entry.getValue());

			// 首先序列化Obj
			StringWriter sw = new StringWriter();
			marshaller.marshal(root, new StreamResult(sw));
			String xml = sw.toString();

			boolean result = LoginkService.sendXml(ActionType.LOGINK_CN_FREIGHTCHARGES.toString(), xml);
			String status = result == true ? "Y" : "N";
			for (Tbplateformcash cash : entry.getValue()) {
				cash.setSendEmp(AppUtils.getLoginUserName());
				cash.setSendTime(AppUtils.getCurrentDate());
				cash.setStatus(status);
				cashFlowDao.update(cash);
			}
		}
	}

	private Root assembleRoot(Collection<Tbplateformcash> cols) {
		Logink logink = SpringHolder.getBean("logink");
		String toaddress = logink.getToaddress();
		Assert.hasText(toaddress, "无车承运人物流交换代码不能为空");

		Tbplateformcash baseInfo = new Tbplateformcash();
		if (!cols.isEmpty()) {
			baseInfo = cols.iterator().next();
		}

		ObjectFactory of = new ObjectFactory();
		Root root = of.createRoot();// 根节点
		Header header = headerBuilder(AppUtils.toString(baseInfo.getSenderCode()), toaddress);
		Body body = bodyBuilder(cols, baseInfo);
		root.getHeaderOrBody().add(header);
		root.getHeaderOrBody().add(body);
		return root;
	}

	private Body bodyBuilder(Collection<Tbplateformcash> cols, Tbplateformcash baseInfo) {

		ObjectFactory of = new ObjectFactory();
		Body body = of.createRootBody();

		List<ShippingNoteList> shippingNoteLists = new ArrayList<>();
		List<Financiallist> financiallists = new ArrayList<>();

		for (Tbplateformcash cash : cols) {
			// ShippingNoteList 节点
			ShippingNoteList snl = of.createRootBodyShippingNoteList();
			snl.setRemark(cash.getRemark());
			snl.setShippingNoteNumber(cash.getShippingNoteNumber());
			shippingNoteLists.add(snl);
		}

		// Financiallist 节点
		Financiallist fl = of.createRootBodyFinanciallist();
		fl.setPaymentMeansCode(baseInfo.getPaymentMeansCode());
		fl.setBankCode(baseInfo.getBankCode());
		fl.setSequenceCode(baseInfo.getSequenceCode());
		fl.setMonetaryAmount(AppUtils.toString(baseInfo.getMonetaryAmount()));
		fl.setDateTime(baseInfo.getDateTime());
		financiallists.add(fl);

		body.setDocumentNumber(baseInfo.getDocumentNumber());
		body.setCarrier(baseInfo.getCarrier());
		body.setVehicleNumber(baseInfo.getVehicleNumber());
		body.setLicensePlateTypeCode(baseInfo.getLicensePlateTypeCode());
		// body.add
		body.getShippingNoteList().addAll(shippingNoteLists);
		body.getFinanciallist().addAll(financiallists);
		return body;
	}

	private Header headerBuilder(String senderCode, String toaddress) {
		Header header = new Root.Header();
		header.setMessageReferenceNumber("JFIEW938230NO2302");
		header.setDocumentName("资金流水单");
		header.setDocumentVersionNumber("2015WCCYR");
		header.setMessageFunctionCode("9");

		header.setSenderCode(senderCode);
		header.setRecipientCode(toaddress);
		header.setMessageSendingDateTime(AppUtils.getCurrentDateString("yyyyMMddHHmmss"));
		return header;
	}

}
